<template>
  <div class="img-canvas-list">
    <!-- Toolbox -->
    <div v-if="checkrole(['admin', 'checker', 'marker'])" class="left-panel-tools">
      <el-radio-group v-model="activateTool" size="mini" @change="handleToolChange">
        <m-image-marker-tool
          v-for="toolOption of toolbox"
          :key="toolOption.name"
          :icon="toolOption.icon"
          :label="toolOption.name"
          :tooltip="toolOption.desc"
        ></m-image-marker-tool>
      </el-radio-group>
    </div>

    <m-image-marker-tooltip></m-image-marker-tooltip>

    <div class="image-container" :style="imgCount > 2 ? 'overflow-y:scroll;' : ''">
      <m-image-marker-view
        v-for="idx of editorIndexs"
        :file="images[idx]"
        :key="'pic-' + idx"
        :annotations="annotation2dMap[idx]"
        :height="imgCount === 1 ? '100%' : 'auto'"
      >
      </m-image-marker-view>
    </div>
  </div>
</template>

<script>
import Paper from 'paper'
import { checkRole } from '@/utils/permission'
import { ToolFactory } from './tools'
import MImageMarkerView from './MImageMarkerView.vue'
import MImageMarkerTool from './MImageMarkerTool.vue'
import MImageMarkerTooltip from './MImageMarkerTooltip.vue'
import MImageMarkerAnnotations from './MImageMarkerAnnotations'
import MImageMarkerRemarks from './MImageMarkerRemarks'

export default {
  components: { MImageMarkerView, MImageMarkerTool, MImageMarkerTooltip, MImageMarkerAnnotations, MImageMarkerRemarks },
  name: 'MImageMarker',
  provide() {
    return { mImageMarker: this }
  },
  inject: ['getConfig'],

  props: {
    task: { type: Object, default: () => ({}) },
    frame: { type: Object, required: true },

    // 图片和标注
    images: { type: Array, required: true },
    annotations: { type: Array, required: true },

    // 选中的 annotation
    selected: { type: Object },
    updateProperty: { type: Function },

    height: Number,
  },
  computed: {
    // 标注框
    markAnnotations() {
      return this.$store.state.markData.markAnnotations
    },
    remarkList() {
      return this.$store.state.markData.remarkList
    },

    config() {
      return this.getConfig()
    },

    imgCount() {
      return this.getConfig().imageCount
    },
    editorIndexs() {
      const length = this.getConfig().imageCount
      return Array.from({ length }).map((v, k) => k)
    },

    updateItem: {
      get() {
        return null
      },
      // anno 属性变化时触发
      set(val) {
        this.$emit('update', val)
      },
    },
  },

  data() {
    return {
      activateTool: 'select',
      toolbox: [],

      annotation2dMap: [],

      pointStrokeWidth: 5,
      lineStrokeWidth: 2,
      polyStrokeWidth: 2,
      rectStrokeWidth: 2,
      attributesTextOpacity: 1,

      pointTextFontSize: 24,

      markType: 0,

      remarkMap: new Map(), // 批注图标

      imageWidth: 0,
      imageHeight: 0,

      remark: null,

      highLightParams: null,
    }
  },

  methods: {
    checkrole: checkRole,

    // 不同的工具绘制不同的对象
    handleToolChange(toolName) {
      console.log(`Change tool ${toolName}`)
      const paperTool = Paper.tools.find((tool) => tool.name === toolName)
      if (!paperTool) console.error('Dont found tool:', toolName)
      paperTool.activate()
      this.paperTool = paperTool
      this.$emit('ToolChanged', toolName)
    },

    // 初始化图片组件事件监听
    initPaperTool() {
      let { paperTool, config } = this
      const { toolbox } = config
      if (paperTool) return
      console.log('Initial paper tool')
      const toolOptions = []
      const paperTools = Object.keys(toolbox).map((toolName) => {
        const tool = ToolFactory(toolName, toolbox[toolName])
        if (toolName === 'select') {
          paperTool = tool
        }
        toolOptions.push(tool.meta)
        return tool
      })

      this.$once('hook:beforeDestroy', () => paperTools.forEach((tool) => tool.remove()))

      // TODO: 快捷键映射, Vue 取消监听
      paperTool.activate()
      this.paperTool = paperTool
      this.toolbox = toolOptions

      console.log(Paper.tools, toolbox, this.toolbox)
    },

    onAnnotationUpdate(anno) {
      this.$emit('updated', anno)
    },
    onSelectedAnnoChange(anno) {
      this.$emit('selected-change', anno)
    },

    /**
 *
this.selectedObject.mMarkAnnotationId = hitResult.item.mMarkAnnotationId
this.selectedObject.name = _array[0].split(':')[0]
this.selectedObject.a1 = _array[1]
this.selectedObject.a2 = _array[2]
this.selectedObject.a3 = _array[3]
this.selectedObject.a4 = _array[4]
this.selectedObject.a5 = _array[5]
this.selectedObject.a6 = _array[6]
this.selectedObject.a7 = _array[7]
this.selectedObject.a8 = _array[8]
this.selectedObject.b1 = _array[9]
this.selectedObject.b2 = _array[10]
this.selectedObject.b3 = _array[11]
this.selectedObject.b4 = _array[12]
this.selectedObject.b5 = _array[13]
this.selectedObject.b6 = _array[14]
this.selectedObject.b7 = _array[15]
this.selectedObject.b8 = _array[16]
this.selectedObject.type = '2d'
this.selectedObject.remark = this.elementsRemark['ball-' + _array[1] + '-2d-' + _index]?.remark || ''
this.selectedObject.errorType = this.elementsRemark['ball-' + _array[1] + '-2d-' + _index]?.errorType || ''
this.selectedObject.mPoint.x = hitResult.item.customCenter.x
this.selectedObject.mPoint.y = hitResult.item.customCenter.y
// this.selectedObject.elementInstance = hitResult.item.missObject;
this.selectedObject.markType = hitResult.item.markType

const _array = hitResult.item.tag.split(';')
let _d = _array[0].split(':')[1]
for (let i = 1; i <= 9; i++) {
  if (_array[i] && _array[i] != null && _array[i] != '' && _array[i] != 'null') {
    try {
      let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_' + _d + 'd'))
      let _values = jsonObject.values[_array[i]]
      if (_values == null || _values == undefined || _values == '') _values = _array[i]

      let _data = { key: jsonObject.typeDesc, _values }
      this.selectedObject.attributes.push(_data)
    } catch {}
  }
}
 */

    clear_highlight_objects() {
      for (let p = 0; p < this.projects.length; p++) {
        let _project = this.projects[p]
        if (!_project) continue
        for (let i = 0; i < _project.activeLayer.children.length; i++) {
          if (_project.activeLayer.children[i].tag || _project.activeLayer.children[i].typeTag) {
            _project.activeLayer.children[i].selected = false
            if (_project.activeLayer.children[i].point1) {
              _project.activeLayer.children[i].point1.opacity = 0
              _project.activeLayer.children[i].point3.opacity = 0
            }
          }
        }
      }
    },
    // 定位缩放选中矩形并高亮
    highlight_objects(eventSource, selectedObject, isZoom = true, hideOther = false) {
      if (this.$store.state.markData.playStatus.pic) {
        this.highLightParams = null
      } else {
        this.highLightParams = {
          eventSource,
          selectedObject,
          isZoom,
          hideOther,
        }
        return
      }
      this.selectedObject = selectedObject
      // 高亮2D对象
      if (!isZoom && this.selectedObject.position == null) {
        for (let m = 0; m < this.mainLayer.length; m++) {
          if (!this.mainLayer[m]) continue
          let items = this.mainLayer[m].getItems()
          for (let i = 0; i < items.length; i++) {
            if (items[i].tag) {
              let itemA1 = items[i].tag.split(';')[1]
              if (itemA1 == this.selectedObject.a1) {
                items[i].selected = true
                // items[i].project.activeLayer.addChild(items[i]);
                if (items[i].point1) {
                  items[i].point1.opacity = 1
                  items[i].point3.opacity = 1
                }
              } else if (hideOther && items[i].hide) {
                items[i].hide()
              } else if (!hideOther && items[i].show) {
                items[i].show()
              }
            }
          }
        }
      } else {
        for (let m = 0; m < this.mainLayer.length; m++) {
          if (!this.mainLayer[m]) continue
          let items = this.mainLayer[m].getItems()
          this.resetDrawing(m)
          let _path = null
          for (let i = 0; i < items.length; i++) {
            if (items[i].markRemarkId) {
              items[i].textObject.fontSize = this.pointTextFontSize
            } else if (items[i].tag) {
              items[i].selected = false
              if (hideOther && items[i].hide) {
                items[i].hide()
              } else if (!hideOther && items[i].show) {
                items[i].show()
              }
              if (items[i].textObject) items[i].textObject.fontSize = this.pointTextFontSize
              if (items[i].point1) {
                items[i].point1.opacity = 0
                items[i].point3.opacity = 0
              }
              let itemA1 = items[i].tag.split(';')[1]
              if (itemA1 == this.selectedObject.a1 && items[i].markType && items[i].markType == 'rect') {
                _path = items[i]
              }
            }
          }
          if (!_path && !this.selectedObject.position) continue
          let paperElement = _path
          if (!_path && this.selectedObject.position) {
            if (!this.selectedObject.imageIndex || m != parseInt(this.selectedObject.imageIndex)) continue
            let centerPoint = new Paper.Point(this.selectedObject.position.x, this.selectedObject.position.y)

            let ppp = this.rasterLayer[m].localToGlobal(
              new Paper.Point(parseFloat(this.selectedObject.position.x), parseFloat(this.selectedObject.position.y))
            )
            _path = {
              bounds: new Paper.Rectangle(ppp, new Paper.Size(30, 30)),
            }
          }
          let _view = this.projects[m].view
          let _zoomPos = _path.bounds.center
          let _count = 0
          while (
            _view.size.height - _path.bounds.height * 2 > 8 &&
            _view.size.width - _path.bounds.width * 2 > 8 &&
            _count < 20
          ) {
            if (_path.bounds.center.x < _view.bounds.center.x && _path.bounds.center.y < _view.bounds.center.y) {
              _zoomPos = _path.bounds.topLeft
            } else if (_path.bounds.center.x < _view.bounds.center.x && _path.bounds.center.y > _view.bounds.center.y) {
              _zoomPos = _path.bounds.bottomLeft
            } else if (_path.bounds.center.x > _view.bounds.center.x && _path.bounds.center.y > _view.bounds.center.y) {
              _zoomPos = _path.bounds.bottomRight
            } else if (_path.bounds.center.x > _view.bounds.center.x && _path.bounds.center.y < _view.bounds.center.y) {
              _zoomPos = _path.bounds.topRight
            }
            try {
              this.zoom(-3, _zoomPos, m)
              _view = this.projects[m].view
              _count++
            } catch (e) {
              console.debug('highlight_objects', e)
            }
          }
          if (paperElement) {
            paperElement.selected = true
            paperElement.show()
            if (paperElement.point1) {
              paperElement.point1.opacity = 1
              paperElement.point3.opacity = 1
            }
          }
        }
      }
    },
    showMarkAnnotations(mMarkAnnotationIds) {
      for (let m = 0; m < this.mainLayer.length; m++) {
        if (!this.mainLayer[m]) continue
        let items = this.mainLayer[m].getItems()
        for (let i = 0; i < items.length; i++) {
          if (items[i].mMarkAnnotationId) {
            const markAnnotation = items[i]
            if (mMarkAnnotationIds.indexOf(markAnnotation.mMarkAnnotationId) != -1) {
              items[i].show()
            } else {
              items[i].hide()
            }
          }
        }
      }
    },

    // 绘制图片上的标注信息
    createPaths(imageIndex) {
      const annot = this.annotations[imageIndex]
      this.pointStrokeWidth = 5
      let fontSize = 24

      if (annot && !annot.object) {
        return
      }
      if (!this.annotation2dMap[imageIndex]) {
        this.annotation2dMap[imageIndex] = new Map()
      }

      this.mainLayer[imageIndex].activate()

      for (let i = 0; i < annot.object.length; i++) {
        const markType = annot.object[i].markType || 'rect'

        // 获取标注标签原始值
        // ${className}:2;${attr[a_i]};${attr[b_i]};
        annot.object[i].getLabels = function (selectDictLabel, attributeNames) {
          let label = this.name + ':2;'
          for (let j = 1; j < 9; j++) {
            label += this.twoD.other_attributes['a' + j] + ';'
          }
          for (let j = 1; j < 9; j++) {
            label += this.twoD.other_attributes['b' + j] + ';'
          }
          return label
        }

        // 获取标注标签转义，用于网页显示
        // ${className}_-${trackId}-${attr[a_i]}-${attr[b_i]}
        annot.object[i].getLabelDescriptions = function (selectDictLabel, attributeNames) {
          let message = ''
          let jsonObject
          let _values = undefined
          try {
            if (selectDictLabel(attributeNames, markType + '_labelName')) {
              jsonObject = JSON.parse(selectDictLabel(attributeNames, markType + '_labelName'))
              _values = jsonObject.values[this.name]
            } else {
              jsonObject = JSON.parse(selectDictLabel(attributeNames, 'labelName'))
              _values = jsonObject.values[this.name]
            }
          } catch (e) {}
          message += _values === undefined ? this.name : _values

          let pre = ''
          if (selectDictLabel(attributeNames, this.name + '_a1_2d')) pre = this.name + '_'
          else if (selectDictLabel(attributeNames, markType + '_a1_2d')) pre = markType + '_'
          for (let j = 1; j <= 8; j++) {
            if (this.twoD.other_attributes['a' + j] && this.twoD.other_attributes['a' + j] != 'null') {
              try {
                let jsonObject = JSON.parse(selectDictLabel(attributeNames, pre + 'a' + j + '_2d'))
                if (jsonObject.typeName && (jsonObject.typeName == 'track_id' || jsonObject.typeName == 'trackId')) {
                  message += '-' + this.twoD.other_attributes.a1
                } else {
                  let _values = jsonObject.values['' + this.twoD.other_attributes['a' + j]]
                  if (_values === undefined) continue
                  message += '-' + _values
                }
              } catch (e) {}
            }
          }
          for (let j = 1; j <= 8; j++) {
            if (this.twoD.other_attributes['b' + j] && this.twoD.other_attributes['b' + j] != 'null') {
              try {
                let jsonObject = JSON.parse(selectDictLabel(attributeNames, pre + 'b' + j + '_2d'))
                let _values = jsonObject.values[this.twoD.other_attributes['b' + j]]
                if (_values === undefined) continue
                message += '-' + _values
              } catch (e) {}
            }
          }
          return message
        }

        if (markType === 'point' || markType === 'keypoints' || markType === 'onepoint') {
          this.drawPoint(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'range') {
          this.drawRange(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'rect3d') {
          this.drawRect3d(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'rect') {
          this.drawRect(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'rectPoint1') {
          this.drawRectPoint1(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'grid') {
          this.drawGrid(fontSize, imageIndex, annot.object[i])
        } else if (markType === 'line' || markType === 'poly') {
          this.drawPoly(fontSize, imageIndex, annot.object[i], markType === 'line')
        } else {
          this.drawRect(fontSize, imageIndex, annot.object[i])
        }
      }

      // 非矩形框、非多边形放在最上层
      this.mainLayer[imageIndex].children.forEach((child) => {
        if (child.rectPoint1 || !(child.markType === 'rect' || (child.markType === 'poly' && child.closed))) {
          this.mainLayer[imageIndex].addChild(child)
        }
      })
      this.mainLayer[imageIndex].children.forEach((child) => {
        if (child.markType === 'point' || child.markType === 'rectPoint1') {
          this.mainLayer[imageIndex].addChild(child)
        }
      })

      console.log(this.remarkList)

      if (this.remarkList) {
        this.drawRemark(this.remarkList, imageIndex, fontSize)
      }
    },

    showAttributesText2D(show) {
      let opacity = show ? 1 : 0
      for (let m = 0; m < this.mainLayer.length; m++) {
        if (!this.mainLayer[m]) continue
        let items = this.mainLayer[m].getItems()
        for (let i = 0; i < items.length; i++) {
          if (items[i].textObject) {
            items[i].textObject.opacity = opacity
          }
        }
      }
    },
  },
  created() {},
  mounted() {
    this.initPaperTool()
  },

  watch: {
    frame(item) {
      console.log(item)
    },
    annotations(value) {
      // 根据 fileName 分组, 是否需要将 anno-list 添加到 image?
      const annoMap = new Array(this.images.length)
      const idMap = this.images.reduce((pre, cur, idx) => {
        pre[cur.filename] = idx
        annoMap[idx] = []
        return pre
      }, {})
      this.annotations.forEach((anno) => {
        const idx = idMap[anno.fileName]
        annoMap[idx].push(anno)
      })
      this.annotation2dMap = annoMap
    },
  },
}
</script>
<style lang="scss" scoped>
.img-canvas-list {
  height: 100%;
  background: #fff;
  border-bottom: 1px solid #e6ebf5;
  position: relative;

  .left-panel-tools {
    padding: 8px;
    position: absolute;
    left: 20px;
    top: 10px;
  }

  .image-container {
    height: 100%;
  }
}
</style>
